import {
  quicktype,
  InputData,
  jsonInputForTargetLanguage,
  JSONSchemaInput,
  FetchingJSONSchemaStore
} from "quicktype-core";

import type { Options, inferenceFlagNames } from "quicktype-core";

/** 原始参数 */
type OOPT = Partial<
  Pick<Options, (typeof inferenceFlagNames)[0] | "allPropertiesOptional" | "alphabetizeProperties" | "indentation">
>;

export type RendererOptionsType = {
  /** 仅仅生成接口 */
  "just-types": boolean;
  /** type 代替 interface */
  "prefer-types": boolean;
  /** 将属性名称转换为javascript格式 */
  "nice-property-names": boolean;
  /** 使用联合类型代替 enum */
  "prefer-unions": boolean;
  /** 对于单个值的字符串枚举, 使用 string 而不是 enum  */
  "prefer-const-values": boolean;
  /** 变量命名风格 */
  "acronym-style": string;
};

/** 转换配置 */
export type JSON2TypeOpt = OOPT & {
  /** 转换目标语言 */
  lang: string;
  /** 生成的类型名称 */
  typeName: string;
  /** JSON 字符串 */
  jsonString: string;
  /** 生成配置 */
  rendererOptions?: Partial<RendererOptionsType>;
};

/** JSONSchema 转换 */
export const quicktypeJSONSchema = async (opt: JSON2TypeOpt) => {
  const schemaInput = new JSONSchemaInput(new FetchingJSONSchemaStore());

  await schemaInput.addSource({ name: opt.typeName, schema: opt.jsonString });

  const inputData = new InputData();
  inputData.addInput(schemaInput);

  return await quicktype({
    inputData,
    ...opt
  });
};

/** JSON转换 */
export const quicktypeJSON = async (opt: JSON2TypeOpt) => {
  const jsonInput = jsonInputForTargetLanguage(opt.lang);

  await jsonInput.addSource({
    name: opt.typeName,
    samples: [opt.jsonString]
  });

  const inputData = new InputData();
  inputData.addInput(jsonInput);

  return await quicktype({
    inputData,
    ...opt
  });
};
